package com.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.model.auto.*;
import com.model.auto.req.StuMajorResultReq;
import com.model.auto.req.StuMajorResultReq.MathTest;
import com.service.*;
import com.util.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生专业方向结果关系表 前端控制器
 * </p>
 *
 * @author astupidcoder
 * @since 2022-09-14
 */
@RestController
@RequestMapping("/stuMajorResult")
@Slf4j
public class StuMajorResultController{

    @Autowired
    private IMajorTestRelService majorTestRelService;
    @Autowired
    private IStuMajorRelService stuMajorRelService;
    @Autowired
    private IStuSubjectRelService stuSubjectRelService;
    @Autowired
    private IMajorSubjectRelService majorSubjectRelService;
    @Autowired
    private IMajorCategoryInfoService majorCategoryInfoService;

    @PostMapping("/showResult")
    public R showResult(@RequestBody StuMajorResultReq stuMajorResultReq) {
//        System.out.println("这是传过来的" + stuMajorResultReq+"数量"+stuMajorResultReq.getStuMajorRel().size());
        List<Map<String, Object>> result = new ArrayList<>();
        stuMajorResultReq.getStuMajorRel().forEach(a->{
            if (a.getScore()==null&&a.getLevel()==2){
                a.setScore(0);
            }
        });
        List<MajorCategoryInfo> list=majorCategoryInfoService.list(new LambdaQueryWrapper<MajorCategoryInfo>()
                        .eq(MajorCategoryInfo::getCatType, 1)
                    .select(MajorCategoryInfo::getId,MajorCategoryInfo::getName)
        );

        List<MajorSubjectRel> majorSubjects=majorSubjectRelService.list(new LambdaQueryWrapper<MajorSubjectRel>()
                .isNotNull(MajorSubjectRel::getRelation)
                .select(MajorSubjectRel::getMajorCategoryId,MajorSubjectRel::getSubjectId,MajorSubjectRel::getRelation)
        );
        stuMajorResultReq.getStuMajorRel().forEach(i -> {
            HashMap<String, Object> object = new HashMap<>();
            list.forEach(m->{
                if (m.getId().equals(i.getId())){
                    if (i.getScore() != null) {
                        object.put("majorId", i.getId());
                        object.put("majorName", m.getName());
                        object.put("intention", i.getScore());
                        List<Float> Proficiencys = new ArrayList<>();
                        for (StuSubjectRel stuSubjectRel : stuMajorResultReq.getStuSubjectRel()) {
                            majorSubjects.forEach(subje->{
                                if (subje.getMajorCategoryId().equals(i.getId())&&subje.getSubjectId().equals(stuSubjectRel.getId())){
                                        float Proficiency1 = (stuSubjectRel.getScore() * subje
                                                .getRelation()) / 5;
                                        Proficiencys.add(Proficiency1);
                                }
                            });
                        }
                        float Proficiency = 0;
                        if (Proficiencys.size() > 0) {
                            List<Float> collect = Proficiencys.stream()
                                    .sorted(Comparator.reverseOrder())
                                    .limit(3)
                                    .collect(Collectors.toList());
                            Optional<Float> reduce = collect.stream().reduce(Float::sum);
                            Proficiency = reduce.get() / 3;
                        }
                        object.put("Proficiency", Proficiency);

                        List<Float> Fitnesss = new ArrayList<>();
                        for (MathTest mathTest : stuMajorResultReq.getMathTests()) {
                            MajorTestRel majorTestRel = majorTestRelService.getOne(new LambdaQueryWrapper<MajorTestRel>()
                                    .eq(MajorTestRel::getMajorCategoryId, i.getId()));
                            if (majorTestRel != null) {
                                if (mathTest.getTopicGroupCode().equals("S")) {
                                    float s = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getSScore()) / 10;
                                    Fitnesss.add(s);
                                } else if (mathTest.getTopicGroupCode().equals("E")) {
                                    float e = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getEScore()) / 10;
                                    Fitnesss.add(e);
                                } else if (mathTest.getTopicGroupCode().equals("C")) {
                                    float c = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getCScore()) / 10;
                                    Fitnesss.add(c);
                                } else if (mathTest.getTopicGroupCode().equals("R")) {
                                    float r = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getRScore()) / 10;
                                    Fitnesss.add(r);
                                } else if (mathTest.getTopicGroupCode().equals("I")) {
                                    float I = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getIScore()) / 10;
                                    Fitnesss.add(I);
                                } else if (mathTest.getTopicGroupCode().equals("A")) {
                                    float a = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getAScore()) / 10;
                                    Fitnesss.add(a);
                                }
                            }
                        }
                        float Fitness = 0;
                        if (Fitnesss.size() > 0) {
                            List<Float> collect = Fitnesss.stream()
                                    .sorted(Comparator.reverseOrder())
                                    .limit(3)
                                    .collect(Collectors.toList());
                            Fitness = (float) ((collect.get(0)*0.5)+(collect.get(1)*0.3)+(collect.get(2)*0.2));
                        }
                        object.put("Fitness", Fitness);
                        if (object.get("intention") != null && object.get("Proficiency") != null && object.get("Fitness") != null) {
                            float recommend= (float) ((Float.parseFloat(object.get("intention").toString())*0.2)+((float) object.get("Proficiency")*0.3)+((float) object.get("Fitness")*0.5));
                             object.put("recommend", recommend);
                        }
                        result.add(object);
                    }
                }
            });



        });
        for (int i = result.size() - 1; i >= 0; i--) {
            if (result.get(i).get("intention") == null || result.get(i).get("intention").equals("0")) {
                result.remove(i);
            }
        }


        List<Map<String, Object>> collect = result.stream()
                .sorted(Comparator.comparing(StuMajorResultController::comparingRecommend)
                        .reversed().thenComparing(StuMajorResultController::comparingFitness)
                        .thenComparing(StuMajorResultController::comparingProficiency)
                        .thenComparing(StuMajorResultController::comparingIntention)

                ).limit(20).collect(Collectors.toList());
        return R.ok(collect);
    }

    @PostMapping("/showResultV2")
    public R showResultV2(@RequestBody StuMajorResultReq req) {
        try{
            List<StuMajorRel> stuMajorList = stuMajorRelService.list(new LambdaQueryWrapper<StuMajorRel>()
                    .eq(StuMajorRel::getStuId, req.getStuId()).isNotNull(StuMajorRel::getMajorCode).gt(StuMajorRel::getScore,0));

            Long subCount = stuSubjectRelService.count(new LambdaQueryWrapper<StuSubjectRel>()
                    .eq(StuSubjectRel::getStuId, req.getStuId()).gt(StuSubjectRel::getScore,0));
            if(CollectionUtils.isEmpty(stuMajorList) || subCount == 0L || CollectionUtils.isEmpty(req.getMathTests())){
                return R.ok();
            }
            List<MajorCategoryInfo> categoryList=majorCategoryInfoService.list(new LambdaQueryWrapper<MajorCategoryInfo>()
                    .eq(MajorCategoryInfo::getCatType, 1)
                    .eq(MajorCategoryInfo::getLevel, 2)
            );
            List<Map<String, Object>> result = new ArrayList<>();
            for(MajorCategoryInfo majorCategory:categoryList){
                HashMap<String, Object> object = new HashMap<>();
                object.put("majorId", majorCategory.getId());
                object.put("majorName", majorCategory.getName());

                for(StuMajorRel stuMajor:stuMajorList){
                    if(majorCategory.getCode().equals(stuMajor.getMajorCode())){
                        object.put("intention", stuMajor.getScore());
                    }
                }
                if(Objects.isNull(object.get("intention"))){
                    object.put("intention", 0);
                }
                if(StringUtils.hasText(majorCategory.getCode())){
                    Float proficiency = stuSubjectRelService.getProficiency(req.getStuId(), majorCategory.getCode());
                    object.put("Proficiency", jisuan(proficiency));
                }else{
                    object.put("Proficiency", 0f);
                }

                List<Float> Fitnesss = new ArrayList<>();
                for (MathTest mathTest : req.getMathTests()) {
                    MajorTestRel majorTestRel = majorTestRelService.getOne(new LambdaQueryWrapper<MajorTestRel>()
                            .eq(MajorTestRel::getMajorCategoryCode, majorCategory.getCode()));
                    if (majorTestRel != null) {
                        if (mathTest.getTopicGroupCode().equals("S")) {
                            float s = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getSScore()) / 10;
                            Fitnesss.add(s);
                        } else if (mathTest.getTopicGroupCode().equals("E")) {
                            float e = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getEScore()) / 10;
                            Fitnesss.add(e);
                        } else if (mathTest.getTopicGroupCode().equals("C")) {
                            float c = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getCScore()) / 10;
                            Fitnesss.add(c);
                        } else if (mathTest.getTopicGroupCode().equals("R")) {
                            float r = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getRScore()) / 10;
                            Fitnesss.add(r);
                        } else if (mathTest.getTopicGroupCode().equals("I")) {
                            float I = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getIScore()) / 10;
                            Fitnesss.add(I);
                        } else if (mathTest.getTopicGroupCode().equals("A")) {
                            float a = (Float.parseFloat(mathTest.getUnitScore()) * majorTestRel.getAScore()) / 10;
                            Fitnesss.add(a);
                        }
                    }
                }
                float Fitness = 0;
                if (Fitnesss.size() > 0) {
                    List<Float> collect = Fitnesss.stream()
                            .sorted(Comparator.reverseOrder())
                            .limit(3)
                            .collect(Collectors.toList());
                    Fitness = (float) ((collect.get(0)*0.6)+(collect.get(1)*0.3)+(collect.get(2)*0.2));
                    Fitness = jisuan(Fitness);
                }
                object.put("Fitness", Fitness);
                if (object.get("intention") != null && object.get("Proficiency") != null && object.get("Fitness") != null) {
                    float recommend= (float) ((Float.parseFloat(object.get("intention").toString())*0.2)+((float) object.get("Proficiency")*0.3)+((float) object.get("Fitness")*0.5));
                    object.put("recommend", jisuan(recommend));
                }
                result.add(object);
            }
            List<Map<String, Object>> collect = result.stream()
                    .sorted(Comparator.comparing(StuMajorResultController::comparingRecommend)
                            .reversed().thenComparing(StuMajorResultController::comparingFitness)
                            .thenComparing(StuMajorResultController::comparingProficiency)
                            .thenComparing(StuMajorResultController::comparingIntention)
                    ).limit(20).collect(Collectors.toList());
            return R.ok(collect);
        }catch (Exception e){
            log.error("发生异常：", e);
            return R.error("发生异常");
        }
    }

    /**
     * 将小数位小于0.5转化为0.5   大于0.5的进1
     * @param num
     * @return
     */
    private float jisuan(float num) {
        double decimalPart = num % 1;
        if (decimalPart < 0.5) {
            return (float)((int)num + 0.5);
        } else {
            return (float)(int)num + 1;
        }
    }

    private static Integer comparingIntention(Map<String, Object> map) {
        return (Integer) map.get("intention");
    }

    private static Float comparingRecommend(Map<String, Object> map) {
        return (Float) map.get("recommend");
    }

    private static Float comparingProficiency(Map<String, Object> map) {
        return (Float) map.get("Proficiency");
    }

    private static Float comparingFitness(Map<String, Object> map) {
        return (Float) map.get("Fitness");
    }
}
